#!/bin/bash
# Generally speaking, the script will:
# - make sure the ingress minikube addon is enabled
# - make sure the script and repo version equals the deployed cluster
# - launch a orchest-ctl pod in-cluster
# - wait for it to be ready
# - attach to it and run the CLI command
# - cleanup on exit


# All issued minikube kubectl commands could be substituted by kubectl
# to make this work with non minikube clusters, but some sections of
# this bash script assume minikube.
MINIKUBE_MODE=true


if $MINIKUBE_MODE && ! minikube addons list | grep "ingress " | grep "enabled" > /dev/null ; then
    echo "The minikube ingress addon needs to be enabled in order to use Orchest."
    read -p "Have this script install it? Type 'yes' to confirm: " -r 
    if [[ $REPLY =~ ^yes$ ]];
    then
        minikube addons enable ingress
    else
        echo "Cancelling installation."
        exit
    fi
fi

namespace_state=$(minikube kubectl -- get namespace orchest -o \
    jsonpath={.status.phase} 2> /dev/null)
if [ "$namespace_state" == "Terminating" ]; then
    echo "The 'orchest' namespace is being terminated, aborting operation."
    exit 1
fi

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"

# Make sure the orchest namespace exists. Necessary only if Orchest is
# being installed.
minikube kubectl -- create namespace orchest  > /dev/null 2>&1

# Make sure the orchest-resources dependencies are installed. This is
# needed, for example, to create pvcs before deploying orchest-ctl.
# K8S_TODO: don't silence stderr, and make it so that repeating "make
# orchest-resources" will not produce an error.
if [ "$1"  == "install" ]; then
    if [ ! -z "$ENABLE_ROOK_NFS" ]
    then
        echo "Warning, Orchest with NFS on a local deployment is considered" \
            "to be a development environment. It doesn't make much sense to" \
            "use this as a user."
        if [ -z "$NFS_CLAIM_SIZE" ]
        then
            WARNING="This can't be changed later."
            echo "Specify the NFS claim size, leave blank for default (50Gi). ${WARNING}" 
            read -p "Size: " NFS_CLAIM_SIZE
            export NFS_CLAIM_SIZE
        fi
    fi

    echo "Creating orchest-namespace and installing dependencies."
    rm -rf "${DIR}/deploy/bin" > /dev/null
    make -C "${DIR}/deploy" orchest-resources > /dev/null 
    if [ $?  != 0 ]; then
        echo "Failed to install Orchest resources. Installation aborted."
        exit 1
    fi

    echo "Running orchest-ctl."
elif ! minikube kubectl get namespace orchest > /dev/null 2>&1 ; then
    echo "You need to install Orchest before running other commands."
    exit 1
fi

# Script and dependencies, i.e. yaml files.
repo_version=$(git describe --tags --abbrev=0)
# The deployment.
cluster_version=$(minikube kubectl -- get namespace orchest -o \
    jsonpath='{.metadata.labels.version}')

# Will be empty only if Orchest has not been installed yet.
if [ -n "$cluster_version" ]; then
    if [ "$repo_version" != "$cluster_version" ]; then
        msg="The Orchest cluster version (${cluster_version}) is different from this
        repository version (${repo_version}). Make sure those are in sync. To do that,
        checkout the repo at a commit which tag matches the cluster version. For
        example, first run (needed if the cluster is at a more recent version than
        the repository):\n
        "
        echo -e $msg
        echo -e "\tgit pull origin\n"
        echo -e "Then checkout the required release version:\n"
        echo -e "\tgit checkout tags/${cluster_version}"
        exit 1
    fi
fi

# Make sure orchest-ctl has the right permissions.
minikube kubectl -- apply -f "$DIR/deploy/orchest-ctl/rbac" > /dev/null

image="orchest/orchest-ctl:${repo_version}"

set -e

# This is needed because k8s labels follow this regex:
# (([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?').
commands=("install" "start" "stop" "restart" "update" "status" "version" "uninstall")
label="unrecognized"
if [[ " ${commands[*]} " =~ " $1 " ]]; then
    label=$1
elif [ "$1"  == "--help" ]; then
    label="help"
fi
# It's important that the "command" label is set right at creation time,
# which allows to detect conflicting concurrent commands without race
# conditions. Refer to config.STATUS_CHANGING_OPERATIONS if you plan
# changes to this label. TODO: passing an argument containing @ will
# break this.
pod=$(sed -e "s@IMAGE%@$image@g" -e "s@VERSION%@$repo_version@g" \
-e "s@COMMAND%@$label@g" "$DIR/deploy/orchest-ctl/pod.yml" | \
minikube kubectl -- create -n orchest -o name -f -)

# Make sure to cleanup the pod on exit.
function on_exit {
    # Avoid funny race conditions.
    for i in {1..100}; do minikube kubectl -- get -n orchest "${pod}" \
        > /dev/null 2>&1 && break; done
    minikube kubectl -- delete -n orchest "${pod}" > /dev/null 2>&1
}
trap on_exit EXIT

# Necessary because
# https://github.com/kubernetes/kubernetes/issues/83242 Note: not
# sleeping here because not all sleep implementations support floating
# point values, and sleeping for 1s introuces a bad delay UX wise. It
# doesn't go through more than 1 iteration usually.
for i in {1..100}; do minikube kubectl -- get -n orchest "${pod}" \
    > /dev/null 2>&1 && break; done

# Wait for 15mins because the image might need to be pulled. TODO:
# alert the user if a pull happens, then wait.
minikube kubectl -- wait --timeout=15m --for=condition=ready -n orchest "${pod}" \
    > /dev/null 2>&1


# Finally, connect to the pod and run the CLI command. If you are asking
# yoursef why we haven't used kunectl run:
# - https://github.com/kubernetes/kubernetes/issues/27264
# - kubectl run is quite limited in functionality if the pod spec is
# complex
minikube kubectl -- exec \
    -it \
    -n orchest "${pod}" orchest -- orchest "$@"
